#include "intflash.hpp"
#include "hc32_ddl.h"
#include <string.h>

using namespace device;
///> 内部flash操作
intflash::intflash(void)
{
	mSemaphore = new systemos::semaphore();
}

intflash::~intflash(void)
{
	delete mSemaphore;
}

bool intflash::Read(uint32_t uiAddr, uint8_t *ucData, uint16_t usLen)
{
	memcpy(ucData,(uint8_t *)uiAddr,usLen);
	return(true);
}

bool intflash::Write(uint32_t uiAddr, uint8_t *ucData, uint16_t usLen)
{
	volatile uint32_t u32TimeOut;
	volatile uint32_t Buff;
	uint8_t i;
	uint32_t j, l, *k;

	if(uiAddr & 3)
	{
		return(false);
	}
	if(usLen & 3)
	{
		return(false);
	}
	mSemaphore->Take(portMAX_DELAY);
	
	M4_EFM->FAPRT = 0x0123ul;
	M4_EFM->FAPRT = 0x3210ul;
	M4_EFM->FSTP_f.FSTP = 0;
	while(!M4_EFM->FSR_f.RDY);
	M4_EFM->FSCLR = 0x3f;
	i = M4_EFM->FRMC_f.CACHE;
	M4_EFM->FRMC_f.CACHE = 0;
	M4_EFM->FWMC_f.PEMODE = 1;
	M4_EFM->FWMC_f.PEMOD = 1;
	M4_EFM->FSCLR = 0x20;
	M4_EFM->FSCLR = 0x01;
	k = (uint32_t *)uiAddr;
	for(j = 0ul; j < usLen; j += 4)
	{
		l = ucData[j] + (ucData[j + 1] << 8) + (ucData[j + 2] << 16) + (ucData[j + 3] << 24);
		*k = l;
		k++;
	}
	
	M4_EFM->FWMC_f.PEMOD = 0;
	while(!M4_EFM->FSR_f.RDY);
	M4_EFM->FSCLR = 0x10;
	M4_EFM->FWMC_f.PEMODE = 0;
	M4_EFM->FRMC_f.CACHE = i;
	M4_EFM->FAPRT = 0x3210ul;
	M4_EFM->FAPRT = 0x3210ul;
	
	mSemaphore->Give();
	return(true);
}

bool intflash::Erase(uint32_t uiAddr)
{
	uint8_t i;
	mSemaphore->Take(portMAX_DELAY);
	
	M4_EFM->FAPRT = 0x0123ul;
	M4_EFM->FAPRT = 0x3210ul;
	M4_EFM->FSTP_f.FSTP = 0;
	while(!M4_EFM->FSR_f.RDY);
	M4_EFM->FSCLR = 0x3f;
	i = M4_EFM->FRMC_f.CACHE;
	M4_EFM->FRMC_f.CACHE = 0;
	M4_EFM->FWMC_f.PEMODE = 1;
	M4_EFM->FWMC_f.PEMOD = 4;
	*(uint32_t*)uiAddr = 0x12345678u;
	while(!M4_EFM->FSR_f.RDY);
	M4_EFM->FSCLR = 0x00000010;
	M4_EFM->FWMC_f.PEMOD = 0;
	M4_EFM->FWMC_f.PEMODE = 0;
	M4_EFM->FRMC_f.CACHE = i;
	M4_EFM->FAPRT = 0x3210ul;
	M4_EFM->FAPRT = 0x3210ul;
	
	mSemaphore->Give();
	return(true);
}

uint32_t intflash::GetSectorSize(void)
{
	return(INTERFLASH_SECTOR_SIZE);
}
